package at.ac.tuwien.dse.health.messenger;

import at.ac.tuwien.dse.health.entity.*;
import at.ac.tuwien.dse.health.event.annotation.Observe;
import at.ac.tuwien.dse.health.event.type.Event;
import at.ac.tuwien.dse.health.reservation.ReservationCancellation;
import at.ac.tuwien.dse.health.reservation.ReservationConfirmation;
import at.ac.tuwien.dse.health.reservation.ReservationRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import java.io.IOException;
import java.util.Date;

import static at.ac.tuwien.dse.health.entity.MessageType.*;

/**
 * Observes {@link ReservationConfirmation} and {@link ReservationCancellation} {@link Event Events} and creates
 * {@link Message Messages} for the desired recipient.
 *
 * @author Bernhard Nickel
 * @author Gregor Schauer
 * @author Dominik Strasser
 */
@Transactional
public class Messenger {
	private static final Logger LOGGER = LogManager.getLogger(Messenger.class);
	@Inject
	MessageService messageService;

	public static void main(String... args) throws IOException {
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("applicationContext.xml");
		ctx.registerShutdownHook();

		// And now sleep very long...
		for (int i = 0; true; i++) {
			try {
				Thread.sleep(5000);
				System.out.printf("%-5d", i);
			} catch (InterruptedException e) {
				// Who cares...?
			}
		}
	}

	/**
	 * Handles the given {@link ReservationConfirmation} event.
	 *
	 * A confirmation might indicate that a reservation request was successful or not.<br/>
	 * A {@link Message} is created for the {@link Doctor} who sent the request and the {@link Patient} and to the
	 * {@link Hospital} in which the surgery takes place in case of success.
	 *
	 * @param confirmationEvent the event observed
	 */
	@Observe
	public void handleReservationConfirmation(Event<ReservationConfirmation> confirmationEvent) {
		ReservationConfirmation confirmation = confirmationEvent.getValue();
		ReservationRequest request = confirmation.getRequest();
		Date now = new Date();
		SurgerySlot slot = confirmation.getSlotId() != null ? messageService.findSlot(confirmation.getSlotId()) : null;

		Account patientAccount = messageService.findAccount(Patient.class, request.getPatientId());
		Account doctorAccount = messageService.findAccount(Doctor.class, request.getDoctorId());

		messageService.createMessage(confirmation, slot == null ? ERROR : SUCCESS, now, patientAccount, doctorAccount.getUser(), slot);
		messageService.createMessage(confirmation, slot == null ? ERROR : SUCCESS, now, doctorAccount, patientAccount.getUser(), slot);
		if (slot != null) {
			Account hospitalAccount = messageService.findAccount(Hospital.class, slot.getHospital().getId());
			messageService.createMessage(confirmation, SUCCESS, now, hospitalAccount, patientAccount.getUser(), doctorAccount.getUser(), slot);
		}
	}

	/**
	 * Handles the given {@link ReservationCancellation} event.
	 *
	 * A cancellation indicates that a reservation request was deleted successfully.<br/>
	 * A {@link Message} is created for the {@link Doctor} who sent the request and the {@link Patient} and to the
	 * {@link Hospital} in which the surgery would have taken place in.
	 *
	 * @param cancellationEvent the event observed
	 */
	@Observe
	public void handleReservationCancellation(Event<ReservationCancellation> cancellationEvent) {
		ReservationCancellation cancellation = cancellationEvent.getValue();
		Date now = new Date();

		Account patientAccount = messageService.findAccount(Patient.class, cancellation.getPatientId());
		Account doctorAccount = messageService.findAccount(Doctor.class, cancellation.getPatientId());
		Account hospitalAccount = messageService.findAccount(Hospital.class, cancellation.getHospitalId());

		messageService.createMessage(cancellation, INFO, now, patientAccount, doctorAccount.getUser());
		messageService.createMessage(cancellation, INFO, now, doctorAccount, patientAccount.getUser());
		messageService.createMessage(cancellation, INFO, now, hospitalAccount, patientAccount.getUser(), doctorAccount.getUser());
	}
}
